package org.stragma.apply.modules

import org.kiama.rewriting._
import org.kiama.rewriting.Rewriter.{rule,rulefs,all,attempt,oncetd,Strategy,Term,term,topdown,fail}

import org.stragma.apply.signatures._
import org.stragma.apply.signatures.Apply._
import org.stragma.apply.signatures.{TBase}
import org.stragma.apply.signatures.TBase._

object ApplyStrategies {
	/*
	 * Port of strategy ->  topdownstopping(s) = s <+ all(try(topdownstopping(s)))
	 */
	def topdownstopping(s : => Strategy) : Strategy = s <+ all(attempt(topdownstopping(s)))
	
	/*
	 * Return the lesser of two strings when compared
	 * Port of strategy -> minstring = ?(i,j) ; if <leqS>(i,j) then !i else !j end
	 */
	def minstring = rulefs {
		case (arg0 : String,arg1 : String) => 
			try {
				if (arg0.toInt < arg1.toInt) 
					arg0 
				else 
					arg1
			} catch {
				case e : Exception =>
					if (arg0 < arg1) arg0 else arg1
			}
	}
	
	/*
	 * Return the greater of two strings when compared
	 * Port of strategy ->  maxstring = ?(i,j) ; if <geqS>(i,j) then !i else !j end
	 */
	def maxstring = rulefs {
		case (arg0 : String,arg1 : String) => 
			try {
				if (arg0.toInt > arg1.toInt) 
					arg0 
				else 
					arg1
			} catch {
				case e : Exception =>
					if (arg0 > arg1) arg0 else arg1
			}
	}
	
	/*
	 * Port of strategy -> contains(|t) = oncetd(?t)
	 */
	def contains(t : Term) : Strategy = {
		val strat = rulefs {
			case e : Term if(e == t) =>
				e
		}
		oncetd(strat)
	}
	
	/*
	 * Port of strategy ->  attribute(a) = ( ?e{t*} ; where(<fetch-elem(a)> t* => t) ; !t ) <+ fetch-elem(a)
	 * Note: We do not need to implement the ?e{t*} part of the strategy because in our implementation
	 * attributes are treated as an inner list of the TBase type so no conversion is required
	 */
	def attribute(a : => Strategy) = fetch_elem(a)
	
	/*
	 * Port of strategy -> propagate-attributes = topdown(try(do-propagate-attributes))
	 */
	def propogate_attributes = topdown(attempt(do_propogate_attributes))
	
	/*
	 * Port of strategy ->   do-propagate-attributes = ?Attribute(x,s); topdown(try(add-propagated-attribute(|x)))
	 */
	def do_propogate_attributes = rulefs {
		case Attribute(x,s) => 
			topdown(attempt(add_propogated_attribute(x)))
	}
	
	/*
	 * Definition of rules for apply strategies in Stratego module
	 * apply-assertion(|a) : a -> True()
	 */
	def apply_assertion(a : Term) = rulefs {
		case b : Term if (a==b) => 
			True()
		case _ => 
			False()
	}
	
	/*
	 * Definition of rules for apply strategies in Stratego module
	 * add-propagated-attribute(|a) : e{a*} -> e{a, a*}
	 */
	def add_propogated_attribute(a : Term) = rulefs {
		// Note here that we match any term because e{a*} in Stratego
		// matches a term with 0 or more attributes, the syntax for
		// matching 1 term is e{a}
		case t : TBase =>
			t.addAttributeToBeginning(a)
			t
	}
}